/*!
 ICanHaz.js version 0.10.2 -- by @HenrikJoreteg
 More info at: http://icanhazjs.com
 */
(function () {
    /*
     mustache.js — Logic-less templates in JavaScript

     See http://mustache.github.com/ for more info.
     */

    var Mustache = function () {
        var _toString = Object.prototype.toString;

        Array.isArray = Array.isArray || function (obj) {
            return _toString.call(obj) == "[object Array]";
        }

        var _trim = String.prototype.trim, trim;

        if (_trim) {
            trim = function (text) {
                return text == null ? "" : _trim.call(text);
            }
        } else {
            var trimLeft, trimRight;

            // IE doesn't match non-breaking spaces with \s.
            if ((/\S/).test("\xA0")) {
                trimLeft = /^[\s\xA0]+/;
                trimRight = /[\s\xA0]+$/;
            } else {
                trimLeft = /^\s+/;
                trimRight = /\s+$/;
            }

            trim = function (text) {
                return text == null ? "" :
                    text.toString().replace(trimLeft, "").replace(trimRight, "");
            }
        }

        var escapeMap = {
            "&": "&amp;",
            "<": "&lt;",
            ">": "&gt;",
            '"': '&quot;',
            "'": '&#39;'
        };

        function escapeHTML(string) {
            return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
                return escapeMap[s] || s;
            });
        }

        var regexCache = {};
        var Renderer = function () {};

        Renderer.prototype = {
            otag: "{{",
            ctag: "}}",
            pragmas: {},
            buffer: [],
            pragmas_implemented: {
                "IMPLICIT-ITERATOR": true
            },
            context: {},

            render: function (template, context, partials, in_recursion) {
                // reset buffer & set context
                if (!in_recursion) {
                    this.context = context;
                    this.buffer = []; // TODO: make this non-lazy
                }

                // fail fast
                if (!this.includes("", template)) {
                    if (in_recursion) {
                        return template;
                    } else {
                        this.send(template);
                        return;
                    }
                }

                // get the pragmas together
                template = this.render_pragmas(template);

                // render the template
                var html = this.render_section(template, context, partials);

                // render_section did not find any sections, we still need to render the tags
                if (html === false) {
                    html = this.render_tags(template, context, partials, in_recursion);
                }

                if (in_recursion) {
                    return html;
                } else {
                    this.sendLines(html);
                }
            },

            /*
             Sends parsed lines
             */
            send: function (line) {
                if (line !== "") {
                    this.buffer.push(line);
                }
            },

            sendLines: function (text) {
                if (text) {
                    var lines = text.split("\n");
                    for (var i = 0; i < lines.length; i++) {
                        this.send(lines[i]);
                    }
                }
            },

            /*
             Looks for %PRAGMAS
             */
            render_pragmas: function (template) {
                // no pragmas
                if (!this.includes("%", template)) {
                    return template;
                }

                var that = this;
                var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) {
                    return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
                });

                return template.replace(regex, function (match, pragma, options) {
                    if (!that.pragmas_implemented[pragma]) {
                        throw({message:
                            "This implementation of mustache doesn't understand the '" +
                                pragma + "' pragma"});
                    }
                    that.pragmas[pragma] = {};
                    if (options) {
                        var opts = options.split("=");
                        that.pragmas[pragma][opts[0]] = opts[1];
                    }
                    return "";
                    // ignore unknown pragmas silently
                });
            },

            /*
             Tries to find a partial in the curent scope and render it
             */
            render_partial: function (name, context, partials) {
                name = trim(name);
                if (!partials || partials[name] === undefined) {
                    throw({message: "unknown_partial '" + name + "'"});
                }
                if (!context || typeof context[name] != "object") {
                    return this.render(partials[name], context, partials, true);
                }
                return this.render(partials[name], context[name], partials, true);
            },

            /*
             Renders inverted (^) and normal (#) sections
             */
            render_section: function (template, context, partials) {
                if (!this.includes("#", template) && !this.includes("^", template)) {
                    // did not render anything, there were no sections
                    return false;
                }

                var that = this;

                var regex = this.getCachedRegex("render_section", function (otag, ctag) {
                    // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
                    return new RegExp(
                        "^([\\s\\S]*?)" +         // all the crap at the beginning that is not {{*}} ($1)

                            otag +                    // {{
                            "(\\^|\\#)\\s*(.+)\\s*" + //  #foo (# == $2, foo == $3)
                            ctag +                    // }}

                            "\n*([\\s\\S]*?)" +       // between the tag ($2). leading newlines are dropped

                            otag +                    // {{
                            "\\/\\s*\\3\\s*" +        //  /foo (backreference to the opening tag).
                            ctag +                    // }}

                            "\\s*([\\s\\S]*)$",       // everything else in the string ($4). leading whitespace is dropped.

                        "g");
                });


                // for each {{#foo}}{{/foo}} section do...
                return template.replace(regex, function (match, before, type, name, content, after) {
                    // before contains only tags, no sections
                    var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",

                    // after may contain both sections and tags, so use full rendering function
                        renderedAfter = after ? that.render(after, context, partials, true) : "",

                    // will be computed below
                        renderedContent,

                        value = that.find(name, context);

                    if (type === "^") { // inverted section
                        if (!value || Array.isArray(value) && value.length === 0) {
                            // false or empty list, render it
                            renderedContent = that.render(content, context, partials, true);
                        } else {
                            renderedContent = "";
                        }
                    } else if (type === "#") { // normal section
                        if (Array.isArray(value)) { // Enumerable, Let's loop!
                            renderedContent = that.map(value, function (row) {
                                return that.render(content, that.create_context(row), partials, true);
                            }).join("");
                        } else if (that.is_object(value)) { // Object, Use it as subcontext!
                            renderedContent = that.render(content, that.create_context(value),
                                partials, true);
                        } else if (typeof value == "function") {
                            // higher order section
                            renderedContent = value.call(context, content, function (text) {
                                return that.render(text, context, partials, true);
                            });
                        } else if (value) { // boolean section
                            renderedContent = that.render(content, context, partials, true);
                        } else {
                            renderedContent = "";
                        }
                    }

                    return renderedBefore + renderedContent + renderedAfter;
                });
            },

            /*
             Replace {{foo}} and friends with values from our view
             */
            render_tags: function (template, context, partials, in_recursion) {
                // tit for tat
                var that = this;

                var new_regex = function () {
                    return that.getCachedRegex("render_tags", function (otag, ctag) {
                        return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g");
                    });
                };

                var regex = new_regex();
                var tag_replace_callback = function (match, operator, name) {
                    switch(operator) {
                        case "!": // ignore comments
                            return "";
                        case "=": // set new delimiters, rebuild the replace regexp
                            that.set_delimiters(name);
                            regex = new_regex();
                            return "";
                        case ">": // render partial
                            return that.render_partial(name, context, partials);
                        case "{": // the triple mustache is unescaped
                        case "&": // & operator is an alternative unescape method
                            return that.find(name, context);
                        default: // escape the value
                            return escapeHTML(that.find(name, context));
                    }
                };
                var lines = template.split("\n");
                for(var i = 0; i < lines.length; i++) {
                    lines[i] = lines[i].replace(regex, tag_replace_callback, this);
                    if (!in_recursion) {
                        this.send(lines[i]);
                    }
                }

                if (in_recursion) {
                    return lines.join("\n");
                }
            },

            set_delimiters: function (delimiters) {
                var dels = delimiters.split(" ");
                this.otag = this.escape_regex(dels[0]);
                this.ctag = this.escape_regex(dels[1]);
            },

            escape_regex: function (text) {
                // thank you Simon Willison
                if (!arguments.callee.sRE) {
                    var specials = [
                        '/', '.', '*', '+', '?', '|',
                        '(', ')', '[', ']', '{', '}', '\\'
                    ];
                    arguments.callee.sRE = new RegExp(
                        '(\\' + specials.join('|\\') + ')', 'g'
                    );
                }
                return text.replace(arguments.callee.sRE, '\\$1');
            },

            /*
             find `name` in current `context`. That is find me a value
             from the view object
             */
            find: function (name, context) {
                name = trim(name);

                // Checks whether a value is thruthy or false or 0
                function is_kinda_truthy(bool) {
                    return bool === false || bool === 0 || bool;
                }

                var value;

                // check for dot notation eg. foo.bar
                if (name.match(/([a-z_]+)\./ig)) {
                    var childValue = this.walk_context(name, context);
                    if (is_kinda_truthy(childValue)) {
                        value = childValue;
                    }
                } else {
                    if (is_kinda_truthy(context[name])) {
                        value = context[name];
                    } else if (is_kinda_truthy(this.context[name])) {
                        value = this.context[name];
                    }
                }

                if (typeof value == "function") {
                    return value.apply(context);
                }
                if (value !== undefined) {
                    return value;
                }
                // silently ignore unkown variables
                return "";
            },

            walk_context: function (name, context) {
                var path = name.split('.');
                // if the var doesn't exist in current context, check the top level context
                var value_context = (context[path[0]] != undefined) ? context : this.context;
                var value = value_context[path.shift()];
                while (value != undefined && path.length > 0) {
                    value_context = value;
                    value = value[path.shift()];
                }
                // if the value is a function, call it, binding the correct context
                if (typeof value == "function") {
                    return value.apply(value_context);
                }
                return value;
            },

            // Utility methods

            /* includes tag */
            includes: function (needle, haystack) {
                return haystack.indexOf(this.otag + needle) != -1;
            },

            // by @langalex, support for arrays of strings
            create_context: function (_context) {
                if (this.is_object(_context)) {
                    return _context;
                } else {
                    var iterator = ".";
                    if (this.pragmas["IMPLICIT-ITERATOR"]) {
                        iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
                    }
                    var ctx = {};
                    ctx[iterator] = _context;
                    return ctx;
                }
            },

            is_object: function (a) {
                return a && typeof a == "object";
            },

            /*
             Why, why, why? Because IE. Cry, cry cry.
             */
            map: function (array, fn) {
                if (typeof array.map == "function") {
                    return array.map(fn);
                } else {
                    var r = [];
                    var l = array.length;
                    for(var i = 0; i < l; i++) {
                        r.push(fn(array[i]));
                    }
                    return r;
                }
            },

            getCachedRegex: function (name, generator) {
                var byOtag = regexCache[this.otag];
                if (!byOtag) {
                    byOtag = regexCache[this.otag] = {};
                }

                var byCtag = byOtag[this.ctag];
                if (!byCtag) {
                    byCtag = byOtag[this.ctag] = {};
                }

                var regex = byCtag[name];
                if (!regex) {
                    regex = byCtag[name] = generator(this.otag, this.ctag);
                }

                return regex;
            }
        };

        return({
            name: "mustache.js",
            version: "0.4.0",

            /*
             Turns a template and view into HTML
             */
            to_html: function (template, view, partials, send_fun) {
                var renderer = new Renderer();
                if (send_fun) {
                    renderer.send = send_fun;
                }
                renderer.render(template, view || {}, partials);
                if (!send_fun) {
                    return renderer.buffer.join("\n");
                }
            }
        });
    }();
    /*!
     ICanHaz.js -- by @HenrikJoreteg
     */
    /*global  */
    (function () {
        function trim(stuff) {
            if (''.trim) return stuff.trim();
            else return stuff.replace(/^\s+/, '').replace(/\s+$/, '');
        }

        // Establish the root object, `window` in the browser, or `global` on the server.
        var root = this;

        var ich = {
            VERSION: "0.10.2",
            templates: {},

            // grab jquery or zepto if it's there
            $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null,

            // public function for adding templates
            // can take a name and template string arguments
            // or can take an object with name/template pairs
            // We're enforcing uniqueness to avoid accidental template overwrites.
            // If you want a different template, it should have a different name.
            addTemplate: function (name, templateString) {
                if (typeof name === 'object') {
                    for (var template in name) {
                        this.addTemplate(template, name[template]);
                    }
                    return;
                }
                if (ich[name]) {
                    console.error("Invalid name: " + name + ".");
                } else if (ich.templates[name]) {
                    console.error("Template \"" + name + "  \" exists");
                } else {
                    ich.templates[name] = templateString;
                    ich[name] = function (data, raw) {
                        data = data || {};
                        var result = Mustache.to_html(ich.templates[name], data, ich.templates);
                        return (ich.$ && !raw) ? ich.$(trim(result)) : result;
                    };
                }
            },

            // clears all retrieval functions and empties cache
            clearAll: function () {
                for (var key in ich.templates) {
                    delete ich[key];
                }
                ich.templates = {};
            },

            // clears/grabs
            refresh: function () {
                ich.clearAll();
                ich.grabTemplates();
            },

            // grabs templates from the DOM and caches them.
            // Loop through and add templates.
            // Whitespace at beginning and end of all templates inside <script> tags will
            // be trimmed. If you want whitespace around a partial, add it in the parent,
            // not the partial. Or do it explicitly using <br/> or &nbsp;
            grabTemplates: function () {
                var i,
                    l,
                    scripts = document.getElementsByTagName('script'),
                    script,
                    trash = [];
                for (i = 0, l = scripts.length; i < l; i++) {
                    script = scripts[i];
                    if (script && script.innerHTML && script.id && (script.type === "text/html" || script.type === "text/x-icanhaz")) {
                        ich.addTemplate(script.id, trim(script.innerHTML));
                        trash.unshift(script);
                    }
                }
                for (i = 0, l = trash.length; i < l; i++) {
                    trash[i].parentNode.removeChild(trash[i]);
                }
            }
        };

        // Export the ICanHaz object for **Node.js**, with
        // backwards-compatibility for the old `require()` API. If we're in
        // the browser, add `ich` as a global object via a string identifier,
        // for Closure Compiler "advanced" mode.
        if (typeof exports !== 'undefined') {
            if (typeof module !== 'undefined' && module.exports) {
                exports = module.exports = ich;
            }
            exports.ich = ich;
        } else {
            root['ich'] = ich;
        }

        if (typeof document !== 'undefined') {
            if (ich.$) {
                ich.$(function () {
                    ich.grabTemplates();
                });
            } else {
                document.addEventListener('DOMContentLoaded', function () {
                    ich.grabTemplates();
                }, true);
            }
        }

    })();
})();